前言
有些时候,我们会发现,[]byte 类型在 struct 中,是必不可少的结构体,因为用了[]byte代表可以存储字节数据,也可以叫做二进制安全的存储。代表可以存储任何数据。
如何才能做到在序列化json的情况下,可以Println出一个可读性的在struct的[]byte呢?
实现
最近我在开发我们的部门的配置服务,需要提供一个配置工具。里面设计的一个struct,有一个[]byte类型,就是用来存储实际数据的。但是我们在这里的时候,我们有一个查看原始数据的需求,因为我们的数据经过了加密,和压缩,最终才会放到该结构体。
简化结构体,这里列举一下例子:
1 | type V []byte |
这里我们看到,我们这里的Value实际就是一个[]byte,我们把这个结构体经过json.Marshal之后推送到远端kv服务中,一切都正常。
但是当我们需要查看的时候,就需要从远端的kv拉回来,经过json.Unmarsha处理,这个时候,我们会发现:
1 | {"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":"MTIzCg=="} |
这里,我们看到Value是一个经过base64加密过的数据,这是因为默认情况下[]byte将会把数据经过base64变成字符串来符合json数据类型。那么我们有什么版本让他显示出原来真是的数据呢?
这里我使用了一个方案,借助多一个数据结构,对T V进行一个重组。
1 | type VO []byte |
定义多一个大体上一致的结构体,注意此时的Value不再是V,而是VO,我们对VO自定义json序列化的行为,那就是把base64的行为给去掉。
这样子,我们得到的数据就会是
1 | {"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":123} |
细心的朋友一定发现了问题所在,那就是Value和ValueReadable怎么进行转换。
因为你存的时候是通过Value进行marshal的,那么你的unmarsha行为一定要对应才能解到正确的数据。
所以这里,就是我们的一个重点,我们需要借助unsafe.Pointer
1 | // because []byte in struct will be base64encode |
我们利用unsafe的指针数据类型,进行一个强制转换,为什么会成功呢,因为在内存对齐的结构上,这2个对象的内存是一致的,所以我们就可以进行强制转换,而不用担心有panic的产生。这只是unsafe指针的一个灵活运用。但是可以达到我们的目的,十分的有效果。
1 | {"PublishTime":1630636657,"PublishDateTime":"2021-09-03 02:37:37.8693941 +0000 UTC m=+0.015759101","Value":123} |
转换后,就可以看到我原本的数据了 123.